package com.learn.springframework.context;

import com.learn.springframework.annotation.Autowired;
import com.learn.springframework.annotation.Controller;
import com.learn.springframework.annotation.Service;
import com.learn.springframework.bean.BeanWrapper;
import com.learn.springframework.bean.config.BeanDefinition;
import com.learn.springframework.bean.support.BeanDefinitionReader;
import com.learn.springframework.bean.support.DefaultListableBeanFactory;
import com.learn.springframework.core.BeanFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ApplicationContext上下文:持有BeanFactory引用、或者叫做门面模式
 *
 * @author MI
 */
public class ApplicationContext implements BeanFactory {

    private DefaultListableBeanFactory registry = new DefaultListableBeanFactory();

    /**
     * 三级缓存
     */
    private Map<String, BeanWrapper> factoryBeanInstanceCache = new HashMap<String, BeanWrapper>();


    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();

    private BeanDefinitionReader reader;

    public ApplicationContext(String... configLocations) {
        // 1、加载配置文件
        reader = new BeanDefinitionReader(configLocations);

        try {
            // 2、解析配置文件，将所有的配置信息封装成BeanDefinition对象
            List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            // 3、缓存所有配置信息
            this.registry.doRegistryBeanDefinition(beanDefinitions);
            // 4、加载非延迟加载的所有Bean
            doLoadInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void doLoadInstance() {
        // 循环调用getBean()方法
        for (Map.Entry<String, BeanDefinition> entry : this.registry.beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            if (!entry.getValue().isLazyInit()) {
                // 最终创建对象由getBean触发
                getBean(beanName);
            }
        }

    }

    /**
     * 从IoC容器中获得一个对象
     *
     * @param beanName
     * @return
     */
    @Override
    public Object getBean(String beanName) {
        // 1、先拿到BeanDefinition配置信息
        BeanDefinition beanDefinition = registry.beanDefinitionMap.get(beanName);
        // 2、反射实例化对象
        Object instance = instanceBean(beanName, beanDefinition);
        // 3、将返回的bean对象封装成BeanWrapper
        BeanWrapper beanWrapper = new BeanWrapper(instance);
        // 4、依赖注入
        populateBean(beanName, beanDefinition, beanWrapper);
        // 5、保存IOC 容器
        this.factoryBeanInstanceCache.put(beanName, beanWrapper);

        return beanWrapper.getWrappedInstance();
    }

    private void populateBean(String beanName, BeanDefinition beanDefinition, BeanWrapper beanWrapper) {
        Object instance = beanWrapper.getWrappedInstance();
        Class<?> clazz = beanWrapper.getWrappedClass();
        if (!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))) {
            return;
        }
        try {
            // 忽略字段的修饰符、不管是private、protected、public、default,正常来讲，普通的OOP编程只能拿到public的属性
            for (Field field : clazz.getDeclaredFields()) {
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
                Autowired autowired = field.getAnnotation(Autowired.class);
                // 如果用户没有自定义beanName,默认就是根据类型注入
                String autowireBeanName = autowired.value().trim();
                if ("".equals(autowireBeanName)) {
                    // 获得接口的类型，作为key待会拿到这个key到ioc容器中取值
                    autowireBeanName = field.getType().getName();
                }

                // 暴力访问，强吻
                field.setAccessible(true);
                if (this.factoryBeanInstanceCache.get(autowireBeanName) == null) {
                    continue;
                }
                // 相当于demoAction.demoService = ioc.get("com.learn.demo.service.DemoService")
                field.set(instance, this.factoryBeanInstanceCache.get(autowireBeanName).getWrappedInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object instanceBean(String beanName, BeanDefinition beanDefinition) {
        String className = beanDefinition.getBeanClassName();
        Object instance = null;
        try {
            Class<?> clazz = Class.forName(className);
            instance = clazz.newInstance();
            // 如果是代理对象，触发AOP的逻辑


            this.factoryBeanObjectCache.put(beanName, instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }


    @Override
    public Object getBean(Class beanClass) {
        return getBean(beanClass.getName());
    }

    public int getBeanDefinitionCount() {
        return this.registry.beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames() {
        return this.registry.beanDefinitionMap.keySet().toArray(new String[0]);
    }
}
